package com.njtoyo.taxi.admin.library.payment.jyb.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JYBCerts {

    private static final String JKS = "JKS";
    private static final String P12 = "P12";
    private static final String PKCS12 = "PKCS12";
    private static final String JCEKS = "JCEKS";
    private static final String JCK = "JCK";
    private static final String PFX = "PFX";
//    public static final String KEY_PATH = "/var/pki/taxi_jyb.pfx";
//    public static final String KEY_PASS = "njtoyo1904";
//    public static final String KEY_PATH = "/Users/pilotpete/Desktop/141302259980451.pfx";
    public static final String KEY_PASS = "123456";
    public static final String KEY_PATH = "/var/pki/141302259980451.pfx";

    /**
     *  获取信息摘要
     * @param textBytes 原信息
     * @param algorithm 算法
     * @return 返回该算法的信息摘要
     * @throws Exception
     */
    public static byte[] msgDigest(byte[] textBytes, String algorithm)
            throws Exception {
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        messageDigest.update(textBytes);
        return messageDigest.digest();
    }

    /**
     * 通过证书获取公钥
     * @param certPath 证书的路径
     * @return 返回公钥
     * @throws Exception
     */
    public static PublicKey getPublicKey(String certPath) throws Exception {
        InputStream streamCert = new FileInputStream(certPath);
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        Certificate cert = factory.generateCertificate(streamCert);
        return cert.getPublicKey();
    }
    /**
     * 通过密钥文件或者证书文件获取私钥
     * @param keyPath  密钥文件或者证书的路径
     * @param passwd   密钥文件或者证书的密码
     * @return 返回私钥
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String keyPath, String passwd)
            throws Exception {
        String keySuffix = keyPath.substring(keyPath.indexOf(".") + 1);
        String keyType = JKS;
        if (keySuffix == null || keySuffix.trim().equals(""))
            keyType = JKS;
        else
            keySuffix = keySuffix.trim().toUpperCase();

        if (keySuffix.equals(P12)) {
            keyType = PKCS12;
        } else if (keySuffix.equals(PFX)) {
            keyType = PKCS12;
        } else if (keySuffix.equals(JCK)) {
            keyType = JCEKS;
        } else
            keyType = JKS;

        return getPrivateKey(keyPath, passwd, keyType);

    }

    /**
     * 通过证书或者密钥文件获取私钥
     * @param keyPath  证书或者密钥文件
     * @param passwd   密钥保存密码
     * @param keyType  密钥保存类型
     * @return    返回私钥
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(
            String keyPath,
            String passwd,
            String keyType)
            throws Exception {


        KeyStore ks = KeyStore.getInstance(keyType);
        char[] cPasswd = passwd.toCharArray();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(keyPath);
            ks.load(fis, cPasswd);
            fis.close();
        } finally {
            if (fis != null) {
                fis.close();
                fis = null;
            }
        }
        Enumeration aliasenum = ks.aliases();
        String keyAlias = null;
        PrivateKey key = null;
        while (aliasenum.hasMoreElements()) {
            keyAlias = (String) aliasenum.nextElement();
            key = (PrivateKey) ks.getKey(keyAlias, cPasswd);
            if (key != null)
                break;
        }
        return key;
    }
    /**
     * 	使用私钥签名
     * @param key 私钥
     * @param b 需要签名的byte 数组
     * @return 返回签名后的byte
     * @throws Exception
     */
    public static byte[] sign(PrivateKey priKey, byte[] b) throws Exception {
        Signature sig = Signature.getInstance("SHA1withRSA");
        sig.initSign(priKey);
        sig.update(b);
        return sig.sign();
    }
    /**
     /**
     *  使用公钥加密
     * @param pubKey 公钥
     * @param plainText 需要加密的 byte 数组
     * @return 返回加密的 byte 数据
     * @throws Exception
     */

    /**
     *  把 数组1 与数组2 相加。
     * @param src 开始数组，
     * @param dst 结束数组
     * @return 返回 开始数组+结束数据
     */
    public static byte[] appendArray(byte[] src, byte[] dst)
    {
        byte[] newBytes = new byte[src.length + dst.length];
        System.arraycopy(src, 0, newBytes, 0, src.length);
        System.arraycopy(dst, 0, newBytes, src.length, dst.length);
        return newBytes;
    }

    /**
     * 获取私钥证书ID
     * @param keyPath
     * @param keypwd
     * @return
     */
    public static String getSignCertId(String keyPath, String keypwd) {
        KeyStore ks = null;
        try {
            String keySuffix = keyPath.substring(keyPath.indexOf(".") + 1);
            String keyType = JKS;
            if (keySuffix == null || keySuffix.trim().equals("")) {
                keyType = JKS;
            } else {
                keySuffix = keySuffix.trim().toUpperCase();
                if (keySuffix.equals(P12)) {
                    keyType = PKCS12;
                } else if (keySuffix.equals(PFX)) {
                    keyType = PKCS12;
                } else if (keySuffix.equals(JCK)) {
                    keyType = JCEKS;
                } else {
                    keyType = JKS;
                }
            }
            ks = KeyStore.getInstance(keyType);
            FileInputStream fis = new FileInputStream(keyPath);
            char[] nPassword = null;
            nPassword = ((null == keypwd) || ("".equals(keypwd.trim()))) ? null
                    : keypwd.toCharArray();

            if (null != ks) {
                ks.load(fis, nPassword);
            }
            fis.close();

            Enumeration aliasenum = ks.aliases();
            String keyAlias = null;
            PrivateKey key = null;
            while (aliasenum.hasMoreElements()) {
                keyAlias = (String) aliasenum.nextElement();
                log.info(keyAlias);
                key = (PrivateKey) ks.getKey(keyAlias, nPassword);
                if (key != null)
                    break;
            }
            X509Certificate cert = (X509Certificate) ks.getCertificate(keyAlias);

            return cert.getSerialNumber().toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 获取证书目录下所有证书
     * @param filePath
     * @return
     */
    public static Map<String, X509Certificate> getValidateCertFromDir(String filePath) {
        CertificateFactory cf = null;
        FileInputStream in = null;
        X509Certificate validateCert = null;
        Map<String, X509Certificate> certMap = new HashMap<String, X509Certificate>();
        try {
            cf = CertificateFactory.getInstance("X.509");
            File fileDir = new File(filePath);
            File[] files = fileDir.listFiles(new CerFilter());
            for (int i = 0; i < files.length; ++i) {
                try {
                    File file = files[i];
                    in = new FileInputStream(file.getAbsolutePath());
                    validateCert = (X509Certificate) cf.generateCertificate(in);
                    certMap.put(validateCert.getSerialNumber().toString(),validateCert);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return certMap;
    }


    static class CerFilter implements FilenameFilter {
        public boolean isCer(String name) {
            return (name.toLowerCase().endsWith(".cer"));
        }

        public boolean accept(File dir, String name) {
            return isCer(name);
        }
    }
}
